package com.example.demoexcel.service.impl;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.text.csv.CsvWriter;
import com.alibaba.excel.EasyExcel;
import com.example.demoexcel.mapper.AreaStationDataMapper;
import com.example.demoexcel.model.AreaStationData;
import com.example.demoexcel.model.NameAndValueInt;
import com.example.demoexcel.service.IAreaStationDataService;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 赵恒
 * @date 2023/7/11
 */
@Service
@Slf4j
public class AreaStationDataServiceImpl extends MppServiceImpl<AreaStationDataMapper, AreaStationData> implements IAreaStationDataService {

    @Resource
    AreaStationDataMapper areaStationDataMapper;

    @Override
    public void readCsvToDatabase(String csvDir) {
        CsvReader csvReader = CsvUtil.getReader();
        // 递归获取文件列表，前提是要保证文件的纯粹性
        List<File> fileList = new ArrayList<>();
        this.getAllExcelFile(csvDir, fileList);
        fileList = fileList.stream().filter(file -> file.getName().endsWith("csv")).collect(Collectors.toList());
        log.info("开始读取");

        // 遍历文件
        try {
            for (File listFile : fileList) {
                FileInputStream fileInputStream = new FileInputStream(listFile);
//                InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "gb2312");
                InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);

                // 读取CSV数据，成为
                List<AreaStationData> areaStationDataList = csvReader.read(inputStreamReader, AreaStationData.class);
                // 直接写入到数据库，以前存在的，则做更新
                this.saveOrUpdateBatchByMultiId(areaStationDataList);
                log.info("文件名：{}， 写入到数据库条数：{}", listFile.getName(), areaStationDataList.size());
                inputStreamReader.close();
                fileInputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        log.info("读取完毕");
    }

    @Override
    public void exportExcel(String excelDir) {
        // 分页查询，一直到查完位置
        List<NameAndValueInt> list = this.group();
        for (NameAndValueInt nameAndValueInt : list) {
            List<AreaStationData> areaStationDataList = new ArrayList<>();
            String name = nameAndValueInt.getName();
            Integer value = nameAndValueInt.getValue();
            log.info("name:{}, value:{}", name, value);

            int allPage = value / 5000 + 1;
            for (int i = 0; i < allPage; i++) {
                List<AreaStationData> dataList = areaStationDataMapper.getByPage(name, i * 5000, 5000);
                areaStationDataList.addAll(dataList);
            }
            String fileName = excelDir +File.separator + name + ".xlsx";
            EasyExcel.write(fileName, AreaStationData.class).sheet("Sheet1").doWrite(areaStationDataList);
            log.info("导出成功");
        }

    }

    @Override
    public void exportCsv(String csvDir) {
        // 分页查询，一直到查完位置
        List<NameAndValueInt> list = this.group();
        for (NameAndValueInt nameAndValueInt : list) {
            List<AreaStationData> areaStationDataList = new ArrayList<>();
            String name = nameAndValueInt.getName();
            Integer value = nameAndValueInt.getValue();
            log.info("name:{}, value:{}", name, value);

            int allPage = value / 5000 + 1;
            for (int i = 0; i < allPage; i++) {
                List<AreaStationData> dataList = areaStationDataMapper.getByPage(name, i * 5000, 5000);
                areaStationDataList.addAll(dataList);
            }

            CsvWriter csvWriter = CsvUtil.getWriter(csvDir + File.separator + name + ".csv", Charset.forName("GB2312"));
            csvWriter.writeBeans(areaStationDataList);
            log.info("导出成功");
        }
    }

    /**
     * 因为给出的CSV文件的字段 天气现象记录，存在很多逗号，需要先进行找出来
     * 判断标准是 逗号数量 超过255个的
     */
    @Override
    public void findErrorLine(String errorDir, String outputFilePath, Charset charset) {
        FileWriter fileWriter = new FileWriter(outputFilePath);
        List<File> fileList = new ArrayList<>();
        this.getAllExcelFile(errorDir, fileList);
        for (File file : fileList) {
            FileReader fileReader = new FileReader(file, "GB2312");
            List<String> lines = fileReader.readLines();
            lines = lines.stream().filter(s -> {
                // 逗号的数量超出255
                List<Integer> indexList = new ArrayList<>();
                char[] chars = s.toCharArray();
                for (int i = 0; i < chars.length; i++) {
                    if (chars[i] == ',') {
                        indexList.add(i);
                    }
                }
                return !s.contains("D_RETAIN_ID") && indexList.size() > 255;
            }).collect(Collectors.toList());
            fileWriter.appendLines(lines);
        }
    }



    @Override
    public List<NameAndValueInt> group() {
        return areaStationDataMapper.group();
    }

    @Override
    public List<AreaStationData> queryByPage() {
        int pageNum = 2;
        int pageSize = 10;
        return areaStationDataMapper.getByPage("57489", (pageNum - 1) * pageSize, pageSize);
    }

    /**
     * 因为错误的字段位于242个，所以只要大于255个逗号的行，全部删除对应的逗号数量，为了保证最后的省市区三级数据是正确的
     * @param txtFilePath 错误文件路径
     * @param csvFilePath 纠正后的csv文件路径
     */
    @Override
    public void handleErrorLine(String txtFilePath, String csvFilePath) {
        FileReader fileReader = new FileReader(txtFilePath);
        FileWriter fileWriter = new FileWriter(csvFilePath);
        fileWriter.write("D_RETAIN_ID,资料标识,入库时间,收到时间,更新时间,资料时间,数据来源,年,月,日,时,区站号(字符),区站号/观测平台标识(数字),纬度,经度,测站高度,气压传感器海拔高度,风速传感器距地面高度,温湿传感器离地面高度,能见度传感器离地面高度,测站类型,测站级别,行政编码,地面限定符（温度数据）,云探测系统,更正报标志,气压,海平面气压,3小时变压,24小时变压,最高本站气压,最高本站气压出现时间,最低本站气压,最低本站气压出现时间,温度/气温,最高气温,最高气温出现时间,最低气温,最低气温出现时间,过去24小时变温,过去24小时最高气温,过去24小时最低气温,露点温度,相对湿度,最小相对湿度,最小相对湿度出现时间,水汽压,过去1小时降水量,过去3小时降水量,过去6小时降水量,过去12小时降水量,过去24小时降水量,人工加密观测降水量描述周期,降水量,蒸发(大型),2分钟平均风向(角度),2分钟平均风速,10分钟平均风向(角度),10分钟平均风速,小时内最大风速的风向,最大风速,最大风速出现时间,瞬时风向(角度),瞬时风速,极大风速的风向(角度),极大风速,极大风速出现时间,过去6小时极大瞬时风向,过去6小时极大瞬时风速,过去12小时极大瞬时风向,过去12小时极大瞬时风速,地面温度,最高地面温度,最高地面温度出现时间,最低地面温度,最低地面温度出现时间,过去12小时地面最低温度,5cm地温,10cm地温,15cm地温,20cm地温,40cm地温,80cm地温,160cm地温,320cm地温,草面(雪面)温度,草面(雪面)最高温度,草面(雪面)最高温度出现时间,草面(雪面)最低温度,草面(雪面)最低温度出现时间,1分钟平均能见度,10分钟平均能见度,最小水平能见度,最小水平能见度出现时间,水平能见度(人工),总云量,低云量,云量(低云或中云),云底高度,云状1,云状2,云状3,云状4,云状5,云状6,云状7,云状8,低云状,中云状,高云状,现在天气,过去天气描述事件周期,过去天气1,过去天气2,地面状态,积雪深度,雪压,第一冻土层上界值,第一冻土层下界值,第二冻土层上界值,第二冻土层下界值,气压质控码,海平面气压质量控制标志,3小时变压质控码,24小时变压质控码,日最高本站气压质控码,日最高本站气压出现时间质控码,日最低本站气压质控码,日最低本站气压出现时间质控码,温度/气温质控码,日最高气温质控码,日最高气温出现时间质控码,1小时内最低气温质控码,小时内最低气温出现时间质控码,24小时变温质控码,过去24小时最高气温质控码,过去24小时最低气温质控码,露点温度质控码,相对湿度质控码,最小相对湿度质控码,最小相对湿度出现时间质控码,水汽压质控码,小时降水量质控码,过去3小时降水量质控码,过去6小时降水量质控码,过去12小时降水量质控码,24小时降水量质控码,人工加密观测降水量描述时间周期质控码,分钟降水量质控码,日蒸发量（大型）质控码,2分钟平均风向质控码值,2分钟平均风速成质控码值,10分钟风向质控码,10分钟平均风速质控码,日最大风速的风向质控码,日最大风速质控码,日最大风速出现时间质控码,瞬时风向(角度)质控码,瞬时风速质控码,日极大风速的风向质控码,日极大风速质控码,日极大风速出现时间质控码,过去6小时极大瞬时风向质控码,过去6小时极大瞬时风速质控码,过去12小时极大瞬时风向质控码,过去12小时极大瞬时风速质控码,地面温度质控码,日最高地面温度质控码,日最高地面温度出现时间质控码,日最低地面温度质控码,日最低地面温度出现时间质控码,过去12小时最低地面温度质控码,5cm地温质控码,10cm地温质控码,15cm地温质控码,20cm地温质控码,40cm地温质控码,80cm地温质控码,160cm地温质控码,320cm地温质控码,草面（雪面）温度质控码,日草面（雪面）最高温度质控码,日草面（雪面）最高温度出现时间质控码,日草面（雪面）最低温度质控码,日草面（雪面）最低温度出现时间质控码,1分钟平均水平能见度质控码,10分钟平均水平能见度质控码,日最小水平能见度质控码,日最小水平能见度出现时间质控码,水平能见度质控码,总云量质控码,低云量质控码,低云或中云的云量质控码,云底高度质控码,云状1质控码,云状2质控码,云状3质控码,云状4质控码,云状5质控码,云状6质控码,云状7质控码,云状8质控码,低云状质控码,中云状质控码,高云状质控码,现在天气质控码,过去天气描述时间周期质控码,过去天气1质控码,过去天气2质控码,地面状态质控码,路面雪层厚度质控码,雪压质控码,第一冻土层上界值质控码,第一冻土层下界值质控码,第二冻土层上界值质控码,第二冻土层下界值质控码,保留字段1,保留字段2,保留字段3,保留字段4,保留字段5,保留字段6,保留字段7,保留字段8,保留字段9,保留字段10,冰雹的最大重量质控码,天气现象检测系统,蒸发水位,地面状态测量方法,积雪深度的测量方法,降水测量方法,冰雹的最大重量,电线积冰-现象,电线积冰-南北方向直径,电线积冰-南北方向厚度,电线积冰-南北方向重量,电线积冰-东西方向直径,电线积冰-东西方向厚度,电线积冰-东西方向重量,电线积冰－风向,电线积冰－风速,天气现象记录,电线积冰-现象质控码,电线积冰-南北方向直径质控码,电线积冰-南北方向厚度质控码,电线积冰-南北方向重量质控码,电线积冰-东西方向直径质控码,电线积冰-东西方向厚度质控码,电线积冰-东西方向重量质控码,电线积冰－风向质控码,电线积冰－风速质控码,站名,省名,地市名,区县名");

        List<String> lines = fileReader.readLines();

        List<String> handles = new ArrayList<>();
        for (String line : lines) {
            // 获取所有的逗号的index
            List<Integer> indexList = new ArrayList<>();
            char[] chars = line.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                if (chars[i] == ',') {
                    indexList.add(i);
                }
            }
            // 找出要删除的逗号的索引
            int deleteCount = indexList.size() - 255;
            if (deleteCount == 0) {
                handles.add(line);
            } else {
                List<Integer> deleteIndexList = new ArrayList<>();

                for (int i = 0; i < indexList.size(); i++) {
                    if (i <= 241) {
                        continue;
                    }
                    deleteIndexList.add(indexList.get(i));
                    if (deleteIndexList.size() == deleteCount) {
                        break;
                    }
                }

                StringBuilder stringBuilder = new StringBuilder(line);
                for (int i = deleteIndexList.size() - 1; i >= 0; i--) {
                    stringBuilder.deleteCharAt(deleteIndexList.get(i));
                }
                handles.add(stringBuilder.toString());
            }


        }
        fileWriter.appendLines(handles);
    }

    @Override
    public void convertEncode(String sourceFile, String endFilePath) {
        FileReader fileReader = new FileReader("D:\\temp\\武汉大数据\\csv\\Q1743.csv", Charset.forName("UTF-8"));

    }

    /**
     * 递归获取某文件夹下的文件集合
     * @param path 文件夹路径
     * @param fileList File list
     */
    private void getAllExcelFile(String path, List<File> fileList) {
        File file = new File(path);
        if (file.isDirectory()) {
            for (File listFile : file.listFiles()) {
                getAllExcelFile(listFile.getAbsolutePath(), fileList);
            }
        } else {
            fileList.add(file);
            return;
        }
    }
}
